package com.gm.app.web;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import javax.persistence.TypedQuery;
import javax.servlet.http.HttpServletRequest;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.support.RequestContextUtils;

import com.gm.app.data.PlaceDAO;
import com.gm.app.model.Address;
import com.gm.app.model.City;
import com.gm.app.model.Contact;
import com.gm.app.model.Country;
import com.gm.app.model.District;
import com.gm.app.model.Indication;
import com.gm.app.model.Place;
import com.gm.app.model.Region;
import com.gm.app.model.Register;
import com.gm.app.model.Resident;
import com.gm.app.model.Street;
import com.gm.spring.context.support.ResourceBundleMessageSource;

@Controller
public class DashboardController {

	private ResourceBundleMessageSource messageSource;

	private <T> T get(TypedQuery<T> query) {
		List<T> list = query.getResultList();
		if (list != null && list.size() > 0) {
			return list.get(0);
		}
		return null;
	}

	interface CSVReader {
		public <T extends Register> T fromCsv(String line, T inst);
	}

	class CSVReader1 implements CSVReader {

		public <T extends Register> T fromCsv(String line, T inst) {
			City poa = get(City.findCitysByDescription("Porto Alegre"));
			if (poa == null) {
				poa = new City();
				poa.setDescription("Porto Alegre");
			}

			int i = 0;
			Contact c;
			Address a;
			Place p;
			for (String str : line.split("\",\"")) {
				String s = str.trim().replaceAll("\"", "");
				if (s.length() > 0)
					switch (i) {
					case 0:
						c = inst.getContact();
						if (c == null) {
							c = new Contact();
							inst.setContact(c);
						}
						c.setName(s);
						break;
					case 1:
						int j = 0;
						String street = "",
						city = "",
						compl = "";
						Integer number = 0;
						for (String part : s.split("[,-]")) {
							switch (j++) {
							case 0:
								street = part.trim();
								break;
							case 1:
								number = Integer.valueOf(part.trim());
								break;
							case 2:
								compl = part.trim();
								break;
							case 3:
								city = part.trim();
							}

						}
						a = inst.getAddress();
						if (a == null) {
							a = get(Address.findAddressesByDescription(street));
							if (a == null) {
								a = new Address();
								a.setDescription(street);
								a.setStNumber(number);
								a.setComplement(compl);
								a.setCity(poa);
							}
							inst.setAddress(a);
						}

						break;
					case 2:
						c = inst.getContact();
						if (c == null) {
							c = new Contact();
							inst.setContact(c);
						}
						c.setHomePhone(s);
						break;
					case 3:
						c = inst.getContact();
						if (c == null) {
							c = new Contact();
							inst.setContact(c);
						}
						c.setCommercialPhone(s);
						break;
					case 4:
						inst.setComments(s);
						break;
					case 5:
						c = inst.getContact();
						if (c == null) {
							c = new Contact();
							inst.setContact(c);
						}
						p = c.getCountry();
						if (p == null) {
							p = get(Country.findCountrysByDescription(s));
							if (p == null) {
								p = new Country();
								p.setDescription(s);
								p.persist();
								c.setCountry((Country) p);
							}
						}
						break;
					}
				;
				i++;
			}
			return inst;
		}
	}

	class CSVReader2 implements CSVReader {
		public <T extends Register> T fromCsv(String line, T inst) {
			City poa = get(City.findCitysByDescription("Porto Alegre"));
			if (poa == null) {
				poa = new City();
				poa.setDescription("Porto Alegre");
			}

			int i = 0;
			Contact c;
			Address a;
			Place p;
			for (String str : line.split("\",\"")) {
				String s = str.trim().replaceAll("\"", "");
				if (s.length() > 0)
					switch (i) {
					case 0:
						c = inst.getContact();
						if (c == null) {
							c = new Contact();
							inst.setContact(c);
						}
						p = c.getCountry();
						if (p == null) {
							p = get(Country.findCountrysByDescription(s));
							if (p == null) {
								p = new Country();
								p.setDescription(s);
								p.persist();
							}
							c.setCountry((Country) p);
						}
						break;
					case 3:
						c = inst.getContact();
						if (c == null) {
							c = new Contact();
							inst.setContact(c);
						}
						c.setName(s);
						break;
					case 4:
						a = inst.getAddress();
						if (a == null) {
							a = get(Address.findAddressesByDescription(s));
							if (a == null) {
								a = new Address();
								a.setStreet(new Street());
								a.getStreet().setDescription(s);
								a.setCity(poa);
							}
							inst.setAddress(a);
						}

						break;
					case 5:
						a = inst.getAddress();
						a.setStNumber(Integer.valueOf(s));
						break;
					case 6:
						a = inst.getAddress();
						a.setComplement(s);
						break;
					case 7:
						/*
						 * String dst = s.replaceAll("\\s*[0-9]+", ""); a =
						 * inst.getAddress(); p = a.getDistrict(); if (p ==
						 * null) { District d = get(District
						 * .findDistrictsByDescription(dst)); if (d == null) { d
						 * = new District(); d.setDescription(dst);
						 * a.setDistrict(d); } }
						 */
						break;
					case 8:
						c = inst.getContact();
						if (c == null) {
							c = new Contact();
							inst.setContact(c);
						}
						c.setHomePhone(s);
						break;
					case 10:
						c = inst.getContact();
						if (c == null) {
							c = new Contact();
							inst.setContact(c);
						}
						c.setCommercialPhone(s);
						break;
					case 13:
						inst.setComments(s);
						break;
					}
				i++;
			}
			inst.getAddress().setDescription(
					PlaceDAO.format(inst.getAddress(), false));
			return inst;
		}
	}

	public <T extends Register> List<T> readCsv(String csv, Class<T> inst,
			CSVReader reader) {
		List<T> list = new ArrayList<T>();
		InputStream is = inst.getResourceAsStream(csv);
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String strLine;
		try {
			strLine = br.readLine();
			while (strLine != null && (strLine = br.readLine()) != null) {
				list.add(reader.fromCsv(strLine, inst.newInstance()));
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		return list;
	}

	@RequestMapping(value = "/dashboard/data/{type}/{id}/{file}", method = RequestMethod.GET)
	public String data(Model map, @PathVariable("id") Integer id,
			@PathVariable("file") String file, @PathVariable("type") String type) {
		CSVReader reader;
		if (id == 1)
			reader = new CSVReader1();
		else
			reader = new CSVReader2();

		Class<? extends Register> c = "indication".equals(type) ? Indication.class
				: Resident.class;

		for (Register r : readCsv("/com/gm/app/data/" + file + ".csv", c,
				reader)) {
			r.merge();
		}

		return "redirect:/";
	}

	@RequestMapping(method = RequestMethod.GET)
	public String view(Model model) {
		return "index";
	}

	@RequestMapping(value = "add", method = RequestMethod.GET)
	public String add(Model model) {
		return "add";
	}

	@RequestMapping(value = "/js/i18n/nls/**/{ns}", method = RequestMethod.GET)
	@ResponseBody
	public String bundle(@PathVariable("ns") String ns, HttpServletRequest req)
			throws JsonGenerationException, JsonMappingException, IOException {
		Locale l = RequestContextUtils.getLocale(req);

		Properties p = ((ResourceBundleMessageSource) this.messageSource)
				.getProperties(l);

		HashMap<String, String> map = new HashMap<String, String>();
		Enumeration<Object> keys = p.keys();
		while (keys.hasMoreElements()) {
			String key = (String) keys.nextElement();
			if (ns != null && ns.length() > 0) {
				if (key.startsWith(ns + ".")) {
					map.put(key, p.getProperty(key));
				}
			} else {
				map.put(key, p.getProperty(key));
			}
		}
		ObjectMapper mapper = new ObjectMapper();

		return mapper.writeValueAsString(map);
	}

	@Autowired
	public void setMessageSource(ResourceBundleMessageSource messageSource) {
		this.messageSource = messageSource;
	}

	@ResponseBody
	@RequestMapping(value = "/lang", method = RequestMethod.GET)
	public String getUserLanguage(
			@RequestHeader(value = "Accept-Language") String lang,
			HttpServletRequest request) {
		Map<String, String> map = new HashMap<String, String>();

		map.put("header", lang);
		map.put("lang", RequestContextUtils.getLocale(request)
				.getISO3Language());
		map.put("country", RequestContextUtils.getLocale(request)
				.getISO3Country());

		try {
			ObjectMapper m = new ObjectMapper();
			return m.writeValueAsString(map);
		} catch (Exception e) {
			return "{exception:" + e.getMessage() + "}";
		}
	}

	@ResponseBody
	@RequestMapping(value = "img", method = RequestMethod.GET)
	public String getImage(@RequestParam(value = "src") String src,
			@RequestParam(value = "src") String fName) {
		try {
			URL url = new URL(src);
			InputStream in = url.openStream();
			OutputStream out = new BufferedOutputStream(new FileOutputStream(
					"maps/" + fName));
			for (int b; (b = in.read()) != -1;) {
				out.write(b);
			}
			out.close();
			in.close();

			return null;

		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;

	}

	@RequestMapping(value = "/dashboard")
	public String index() {
		return "dashboard/index";
	}

	@RequestMapping(value = "/test")
	public String test() {

		Indication i = new Indication();
		i.setContact(new Contact());
		i.setAddress(new Address());

		Address addr = i.getAddress();
		addr.setComplement("212");
		addr.setCountry(new Country());
		addr.setCity(new City());
		addr.setDistrict(new District());
		addr.setState(new Region());
		addr.setStNumber(212);
		addr.setStreet(new Street());
		addr.setZip("90820001");

		addr.getCountry().setDescription("Brasil");
		addr.getCity().setDescription("Cidade");
		addr.getCountry().setDescription("Pais");
		addr.getDistrict().setDescription("Bairro");
		addr.getState().setDescription("estado");
		addr.getStreet().setDescription("rua");

		Contact c = i.getContact();
		c.setCountry(new Country());
		c.setName("Contact");

		c.getCountry().setDescription("Argentina");

		i.merge();

		return "dashboard/index";
	}

	@RequestMapping(value = "/test2")
	public String test2() {
		Indication old = Indication.findAllIndications().get(0);
		
		Address addr = new Address();
		addr.setId(old.getId());
		addr.setVersion(old.getVersion());
		addr.setDescription("updated");

		addr.merge();
		old.setAddress(addr);
		old.merge();

		return "dashboard/index";
	}
}
